/* src/vm/jit/compiler2/alloc/Allocator.hpp - Custom allocator for container

   Copyright (C) 2013
   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO

   This file is part of CACAO.

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   02110-1301, USA.

*/

#ifndef _JIT_COMPILER2_ALLOC_ALLOCATOR
#define _JIT_COMPILER2_ALLOC_ALLOCATOR

#include <memory>
#include "vm/statistics.hpp"

namespace cacao {
namespace jit {
namespace compiler2 {
namespace alloc {

STAT_DECLARE_VAR(std::size_t,comp2_allocated,0)
STAT_DECLARE_VAR(std::size_t,comp2_deallocated,0)
STAT_DECLARE_VAR(std::size_t,comp2_max,0)

std::size_t& current_heap_size();

template<class T, class BaseAllocator = std::allocator<T> >
class Allocator : public BaseAllocator {
public:
	typedef typename BaseAllocator::pointer pointer;
	typedef typename BaseAllocator::size_type size_type;

	Allocator() throw() : BaseAllocator() {}
	Allocator(const Allocator& other) throw() : BaseAllocator(other) {}
	template <class U>
	Allocator(const Allocator<U, typename BaseAllocator::template rebind<U>::other> &other) throw() : BaseAllocator(other) {}
	~Allocator() {}

	/**
	 * @note See @cite MeyersEffectiveSTL2001, Item why this is needed.
	 */
	template<class U>
	struct rebind {
		typedef Allocator<U, typename BaseAllocator::template rebind<U>::other> other;
	};

	pointer allocate(size_type n) {
		pointer r = BaseAllocator::allocate(n);
		current_heap_size() += n;
		STATISTICS(comp2_allocated+=n);
		STATISTICS(comp2_max.max(current_heap_size()));
		return r;
	}

	pointer allocate(size_type n, pointer h) {
		pointer r = BaseAllocator::allocate(n, h);
		current_heap_size() += n;
		STATISTICS(comp2_allocated+=n);
		STATISTICS(comp2_max.max(current_heap_size()));
		return r;
	}

	void deallocate(pointer p, size_type n) throw() {
		BaseAllocator::deallocate(p, n);
		current_heap_size() -= n;
		STATISTICS(comp2_deallocated+=n);
	}
};

} // end namespace alloc
} // end namespace compiler2
} // end namespace jit
} // end namespace cacao

#endif /* _JIT_COMPILER2_ALLOC_ALLOCATOR */


/*
 * These are local overrides for various environment variables in Emacs.
 * Please do not remove this and leave it at the end of the file, where
 * Emacs will automagically detect them.
 * ---------------------------------------------------------------------
 * Local variables:
 * mode: c++
 * indent-tabs-mode: t
 * c-basic-offset: 4
 * tab-width: 4
 * End:
 * vim:noexpandtab:sw=4:ts=4:
 */
